You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

194 lines
6.2 KiB

<script setup lang="ts">
/**
* Order Confirmation Page (/order/confirm/[orderId])
*
* Features:
* - Requires authentication (middleware: auth)
* - Fetches order details from /api/orders/[orderId]
* - Validates order belongs to user (server-side)
* - Validates order status is 'pending'
* - Shows OrderSummary component
* - Shows billing address
* - Warning text before final confirmation
* - "Jetzt verbindlich bestellen" button
* - Redirects to success page after confirmation
*/
definePageMeta({
middleware: 'auth',
layout: 'default',
})
const route = useRoute()
const orderId = computed(() => route.params.orderId as string)
// Order data
const order = ref<any>(null)
const isLoading = ref(false)
const isConfirming = ref(false)
const error = ref<string | null>(null)
// Fetch order details
async function fetchOrder() {
if (!orderId.value) return
isLoading.value = true
error.value = null
try {
order.value = await $fetch(`/api/orders/${orderId.value}`)
// Check order status
if (order.value.status === 'completed') {
// Order already completed - redirect to success page
navigateTo(`/order/success/${orderId.value}`)
return
}
if (order.value.status !== 'pending') {
error.value = `Bestellung kann nicht bestätigt werden. Status: ${order.value.status}`
}
} catch (err: any) {
console.error('Failed to fetch order:', err)
if (err.statusCode === 404) {
error.value = 'Bestellung nicht gefunden'
} else if (err.statusCode === 403) {
error.value = 'Du hast keine Berechtigung, diese Bestellung zu sehen'
} else {
error.value = 'Fehler beim Laden der Bestellung'
}
// Redirect to cart after 3 seconds
setTimeout(() => {
navigateTo('/cart')
}, 3000)
} finally {
isLoading.value = false
}
}
// Confirm order
async function confirmOrder() {
if (!orderId.value) return
isConfirming.value = true
error.value = null
try {
const response = await $fetch(`/api/orders/confirm/${orderId.value}`, {
method: 'POST',
})
if (response.success) {
// Redirect to success page
navigateTo(`/order/success/${orderId.value}`)
}
} catch (err: any) {
console.error('Failed to confirm order:', err)
error.value =
err.data?.message ||
'Fehler beim Bestätigen der Bestellung. Bitte versuche es erneut.'
} finally {
isConfirming.value = false
}
}
// Fetch order on mount
onMounted(() => {
fetchOrder()
})
</script>
<template>
<div>
<CommonHeader />
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Page Header -->
<div class="mb-8 text-center">
<h1 class="text-4xl font-bold text-white mb-2">Bestellung bestätigen</h1>
<p class="text-white/70">Bitte überprüfe deine Bestellung vor der finalen Bestätigung</p>
</div>
<!-- Error Alert -->
<Alert v-if="error" variant="error" class="mb-6">
<AlertTitle>Fehler</AlertTitle>
<AlertDescription>{{ error }}</AlertDescription>
</Alert>
<!-- Loading State -->
<div v-if="isLoading" class="text-center py-12">
<div class="animate-spin rounded-full h-12 w-12 border-4 border-white/20 border-t-white mx-auto mb-4" />
<p class="text-white/60">Lade Bestellung...</p>
</div>
<!-- Order Content -->
<div v-else-if="order" class="space-y-6">
<!-- Order Summary Card -->
<Card class="p-6">
<OrderSummary :order="order" :show-address="true" />
</Card>
<!-- Warning Notice -->
<Alert class="border-yellow-500/50 bg-yellow-500/10">
<div class="flex items-start gap-3">
<svg class="w-5 h-5 text-yellow-500 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z">
</path>
</svg>
<div>
<AlertTitle class="text-yellow-500">Wichtiger Hinweis</AlertTitle>
<AlertDescription class="text-yellow-100/90">
Bitte überprüfe alle Angaben sorgfältig. Nach der Bestätigung ist die
Bestellung verbindlich und kann nicht mehr geändert werden.
</AlertDescription>
</div>
</div>
</Alert>
<!-- Confirmation Button -->
<Card class="p-6">
<div class="space-y-4">
<Button @click="confirmOrder" :disabled="isConfirming" variant="experimenta" size="experimenta"
class="w-full">
<span v-if="!isConfirming" class="flex items-center justify-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>Jetzt verbindlich bestellen</span>
</span>
<span v-else class="flex items-center gap-2">
<div class="animate-spin rounded-full h-4 w-4 border-2 border-white/20 border-t-white" />
Bestätigung läuft...
</span>
</Button>
<p class="text-xs text-white/60 text-center">
Mit dem Klick auf "Jetzt verbindlich bestellen" akzeptierst du unsere
<NuxtLink to="/agb" class="text-experimenta-accent hover:underline">
AGB
</NuxtLink>
und
<NuxtLink to="/datenschutz" class="text-experimenta-accent hover:underline">
Datenschutzerklärung
</NuxtLink>
.
</p>
</div>
</Card>
<!-- Back Link -->
<div class="text-center pt-4">
<NuxtLink to="/checkout" class="text-sm text-experimenta-accent hover:underline">
Zurück zum Warenkorb
</NuxtLink>
</div>
</div>
</div>
</div>
</template>